﻿//========================================================= 
/**@file IDCardCmdDriver.h
 * @brief 二代证阅读器命令驱动
 * 
 * @date 2016-05-04   21:02:01
 * @author Zhyioo 
 * @version 1.0
 */ 
//--------------------------------------------------------- 
#ifndef _LIBZHOUYB_IDCARDCMDDRIVER_H_
#define _LIBZHOUYB_IDCARDCMDDRIVER_H_
//--------------------------------------------------------- 
#include "../CommonCmdDriver.h"
//--------------------------------------------------------- 
namespace zhou_yb {
namespace application {
namespace driver {
//--------------------------------------------------------- 
/// 二代证命令驱动
class IDCardCmdDriver : 
    public CommonCmdDriver, 
    public BaseDevAdapterBehavior<ISdtApi>
{
protected:
    IDCardParser _idParser;
public:
    /**
     * @brief 分隔 yyyyMMddHHmmssSSS 为单个字段
     * @date 2017-02-11 17:07
     * - 格式:
     *  - 分隔符为非数字类型
     *  - yyyyMMdd HHmmssSSS
     *  - yyyy-MM-dd HH:mm:ss.SSS
     *  - yy-M-d
     *  - yy-M-d H:m:s.S
     * .
     * 
     * @param [in] sDate 需要分隔的日期
     * 
     * @retval Year : uint 年份
     * @retval Month : uint 月份
     * @retval Day : uint 天
     * @retval Hour : uint 时
     * @retval Minute : uint 分
     * @retval Second : uint 秒
     * @retval MilliSecond : uint 毫秒
     */
    static void SplitDateToArguments(const ByteArray& sDate, ICommandHandler::Arguments& rlt)
    {
        const size_t FORMAT_LENGTH[] = { 4, 2, 2, 2, 2, 2, 3 };
        const char FORMAT_NAME[][16] = {
            "Year", "Month", "Day",
            "Hour", "Minute", "Second", "MilliSecond"
        };
        const size_t FORMAT_SIZE = 7;
        const char DIGIT[] = "0123456789";
        const ByteArray DIGIT_ARRAY(DIGIT);
        // 重新组合格式
        ByteArray dateArray(sDate);
        ByteBuilder tmp(4);
        size_t index = 0;
        size_t start = 0;
        size_t end = 0;
        size_t len = 0;
        while(!dateArray.IsEmpty() && index < FORMAT_SIZE)
        {
            start = StringConvert::IndexOfAny(dateArray, DIGIT_ARRAY);
            if(start == SIZE_EOF)
                break;

            dateArray = dateArray.SubArray(start);
            end = StringConvert::IndexOfNotAny(dateArray, DIGIT_ARRAY);
            len = _min(end, FORMAT_LENGTH[index]);

            tmp = dateArray.SubArray(0, len);
            dateArray = dateArray.SubArray(len);

            rlt.Put(FORMAT_NAME[index++], tmp.GetString());
        }
    }
    static void ToArguments(IDCardInformation& idInfo, ICommandHandler::Arguments& rlt)
    {
        rlt.Put("Name", idInfo.Name);
        rlt.Put("ID", idInfo.ID);
        rlt.Put("Gender", idInfo.Gender);
        rlt.Put("Nation", idInfo.Nation);
        rlt.Put("Birthday", idInfo.Birthday);
        rlt.Put("Address", idInfo.Address);
        rlt.Put("Department", idInfo.Department);
        rlt.Put("StartDate", idInfo.StartDate);
        rlt.Put("EndDate", idInfo.EndDate);
        rlt.Put("GenderCode", ArgConvert::ToString<uint>(idInfo.GenderCode));
        rlt.Put("NationCode", ArgConvert::ToString<uint>(idInfo.NationCode));
    }
    static void FromArguments(ICommandHandler::Arguments& arg, IDCardInformation& idInfo)
    {
        idInfo.Name = arg["Name"].To<string>();
        idInfo.ID = arg["ID"].To<string>();
        idInfo.Gender = arg["Gender"].To<string>();
        idInfo.Nation = arg["Nation"].To<string>();
        idInfo.Birthday = arg["Birthday"].To<string>();
        idInfo.Address = arg["Address"].To<string>();
        idInfo.Department = arg["Department"].To<string>();
        idInfo.StartDate = arg["StartDate"].To<string>();
        idInfo.EndDate = arg["EndDate"].To<string>();
        idInfo.GenderCode = arg["GenderCode"].To<ushort>();
        idInfo.NationCode = arg["NationCode"].To<ushort>();
    }

    IDCardCmdDriver() : CommonCmdDriver()
    {
        _errGetter.Add(_idParser);
        _logSetter.select(_idParser);

        IdcConvert = NULL;

        _RegisteCMD(IDCardCmdDriver, ParseToTXT);
        _RegisteCMD(IDCardCmdDriver, WltToBMP);
        _RegisteCMD(IDCardCmdDriver, WaitIdCard);
        _RegisteCMD(IDCardCmdDriver, SetWltDecoder);
        _RegisteCMD(IDCardCmdDriver, SetIdcConvert);

        _RegisteExceptCMD(IDCardCmdDriver);
        _RegisteCancelCMD(IDCardCmdDriver);
        _RegisteAdapterCMD(IDCardCmdDriver);
    }
    LC_CMD_ADAPTER_INVOKE(ISdtApi, _idParser);
    LC_CMD_CANCEL(_idParser);
    LC_CMD_EXCEPT()
    {
        EXCEPT_CMD(SetWltDecoder);
        EXCEPT_CMD(SetIdcConvert);
        EXCEPT_CMD(WltToBMP);
        EXCEPT_CMD(ParseToTXT);
        return true;
    }
    /**
     * @brief 读取身份证信息
     * @date 2016-06-11 22:30
     * 
     * @param [in] Timeout : uint [default:DEV_WAIT_TIMEOUT] 等待放卡的超时时间(以毫秒为单位)
     * @param [in] Interval : uint [default:DEV_OPERATOR_INTERVAL] 检测卡片的间隔时间(以毫秒为单位)
     * @param [in] FingerFormat : string [default:Null] 指纹数据格式
     * @param [in] TxtFormat : string [default:Null] TXT数据格式
     * @param [in] WltFormat : string [default:Null] BMP数据格式
     * - 数据格式参数:
     *  - 空 不需要该数据
     *  - Hex
     *  - Base64
     * .
     * @param [in] Bmpfile : string [default:Null] 需要生成的照片路径
     * @param [in] Wltfile : string [default:Null] 需要生成的WLT文件路径
     * 
     * @retval Name : string 姓名
     * @retval ID : string 身份证号
     * @retval Gender : string 性别
     * @retval Nation : string 民族
     * @retval Birthday : string 出生年月
     * @retval Address : string 住址
     * @retval Department : string 签发机关
     * @retval StartDate : string 起始日期
     * @retval EndDate : string 截至日期
     * @retval GenderCode : uint 性别代码
     * @retval NationCode : uint 民族代码
     * @retval Finger : string 指纹数据
     * @retval TxtMSG : string TXT数据
     * @retval WltMSG : string BMP数据(WLT)
     * @retval Bmpfile : string 生成的照片路径
     * @retval Wltfile : string 生成的WLT文件路径
     *
     * @retval IsTxtOK : bool Txt是否生成成功,但是生成Bmp失败
     * @warning 该值不管成功还是失败都存在
     */
    LC_CMD_METHOD(WaitIdCard)
    {
        uint timeoutMs = arg["Timeout"].To<uint>(DEV_WAIT_TIMEOUT);
        uint intervalMs = arg["Interval"].To<uint>(DEV_OPERATOR_INTERVAL);
        string& isTxtOK = rlt.Put("IsTxtOK", "false");

        // 是否需要读取指纹
        string fingerFormat = "";
        bool isFinger = arg.Get("FingerFormat", fingerFormat);
        // 是否需要解析照片
        string bmp = "";
        bool isBmp = arg.Get("Bmpfile", bmp);
        // 是否需要导出WLT数据
        string wltFormat = "";
        bool isExportWlt = arg.Get("WltFormat", wltFormat);
        // 是否需要生成WLT文件
        string wlt = "";
        bool isWlt = arg.Get("Wltfile", wlt);

        ByteBuilder txtMsg(256);
        ByteBuilder bmpMsg(1024);
        ByteBuilder finger(256);

        _idParser.SetWaitTimeout(timeoutMs);
        _idParser.SetOperatorInterval(intervalMs);
        if(!_idParser.GetBaseInformation(txtMsg, (isWlt || isExportWlt || isBmp) ? &bmpMsg : NULL, isFinger ? &finger : NULL))
            return false;

        // 解析基本数据
        IDCardInformation idInfo;
        if(!_idParser.ParseToTXT(txtMsg, idInfo, IdcConvert))
            return false;
        ToArguments(idInfo, rlt);
        isTxtOK = "true";
        // 转换TXT
        string sFormat;
        ByteBuilder formatBuff(64);
        if(arg.Get("TxtFormat", sFormat))
        {
            if(StringConvert::Compare(sFormat.c_str(), "Base64", true))
            {
                Base64_Provider::Encode(txtMsg, formatBuff);
            }
            else
            {
                ByteConvert::ToAscii(txtMsg, formatBuff);
            }
            rlt.Put("TxtMSG", formatBuff.GetString());
        }
        formatBuff.Clear();
        if(isExportWlt)
        {
            if(StringConvert::Compare(sFormat.c_str(), "Base64", true))
            {
                Base64_Provider::Encode(bmpMsg, formatBuff);
            }
            else
            {
                ByteConvert::ToAscii(bmpMsg, formatBuff);
            }
            rlt.Put("WltMSG", formatBuff.GetString());
        }
        // 转换指纹
        if(isFinger)
        {
            ByteBuilder fingerBuff(512);
            if(StringConvert::Compare(fingerFormat.c_str(), "Base64", true))
            {
                Base64_Provider::Encode(finger, fingerBuff);
            }
            else
            {
                ByteConvert::ToAscii(finger, fingerBuff);
            }
            rlt.Put("Finger", fingerBuff.GetString());
        }
        if(isBmp)
        {
            // 解析照片
            if(bmp.length() > 0 && WltDecoder.IsNull())
            {
                _logErr(DeviceError::ArgIsNullErr, "解码器为空");
                return false;
            }
            ByteBuilder finalBmp(8);
            if(!_idParser.ParseToBMP(WltDecoder, bmpMsg, bmp.c_str(), &finalBmp))
                return false;
            rlt.Put("Bmpfile", finalBmp.GetString());
        }
        if(isWlt)
        {
            // 生成 wlt 文件
            if(wlt.length() < 1)
                wlt += ".";
            // 不以 .wlt 结尾
            if(!StringConvert::EndWith(wlt.c_str(), ".wlt", true))
            {
                if(wlt[wlt.length() - 1] != PATH_SEPARATOR)
                    wlt += PATH_SEPARATOR;
                wlt += "zp.wlt";
            }
            ofstream fout;
            fout.open(wlt.c_str(), ios::out | ios::binary);
            ASSERT_FuncErrInfo(!fout.fail(), DeviceError::OperatorErr, "创建wlt照片文件失败");
            /* 照片数据的起始地址 */
            fout.write(bmpMsg.GetString(), bmpMsg.GetLength());
            fout.close();

            rlt.Put("Wltfile", wlt);
        }
        return true;
    }
    /**
     * @brief 将TXT数据转换为字段
     * @date 2018-04-12 21:06
     * 
     * @param [in] TxtMSG : hex 需要解析的信息字段
     * 
     * @retval Name : string 姓名
     * @retval ID : string 身份证号
     * @retval Gender : string 性别
     * @retval Nation : string 民族
     * @retval Birthday : string 出生年月
     * @retval Address : string 住址
     * @retval Department : string 签发机关
     * @retval StartDate : string 起始日期
     * @retval EndDate : string 截至日期
     * @retval GenderCode : uint 性别代码
     * @retval NationCode : uint 民族代码
     */
    LC_CMD_METHOD(ParseToTXT)
    {
        string sTxt = arg["TxtMSG"].To<string>();
        ByteBuilder txtMsg(256);
        DevCommand::FromAscii(sTxt.c_str(), txtMsg);
        ASSERT_FuncErrInfo(!txtMsg.IsEmpty(), DeviceError::ArgIsNullErr, "TXT数据为空");

        // 解析基本数据
        IDCardInformation idInfo;
        ASSERT_FuncErrInfo(_idParser.ParseToTXT(txtMsg, idInfo, IdcConvert),
            DeviceError::OperatorErr, "解析TXT数据失败");

        ToArguments(idInfo, rlt);
        return true;
    }
    /**
     * @brief 将WLT图片数据转为图片
     * @date 2017-09-11 22:39
     * 
     * @param [in] WltMSG : hex 图片WLT数据
     * @warning 数据格式必须为HEX
     *
     * @param [in] Bmpfile : string 需要生成的图片路径
     * 
     * @retval Bmpfile : string 最后生成的图片路径
     */
    LC_CMD_METHOD(WltToBMP)
    {
        string bmp = arg["Bmpfile"].To<string>();
        ByteBuilder photoMsg(1024);
        
        string msg = arg["WltMSG"].To<string>();
        DevCommand::FromAscii(msg.c_str(), photoMsg);

        ASSERT_FuncErrInfo(!photoMsg.IsEmpty(), DeviceError::ArgIsNullErr, "WLT数据为空");

        ByteBuilder finalBmp(16);
        ASSERT_FuncErrInfo(_idParser.ParseToBMP(WltDecoder, photoMsg, bmp.c_str(), &finalBmp),
            DeviceError::OperatorErr, "解码WLT数据失败");

        rlt.Put("Bmpfile", finalBmp.GetString());
        return true;
    }
    /**
     * @brief 设置二代证字符集转换回调函数
     * @date 2016-10-23 21:08
     * 
     * @param [in] IdcConvert : pointer 二代证字符集转换函数地址 IDCardParser::fpIdcConvert
     */
    LC_CMD_METHOD(SetIdcConvert)
    {
        pointer pIdc = arg["IdcConvert"].To<pointer>(NULL);
        IdcConvert = reinterpret_cast<IDCardParser::fpIdcConvert>(pIdc);
        return true;
    }
    /**
     * @brief 设置二代证照片解码器
     * @date 2016-10-23 21:12
     * 
     * @param [in] IWltDecoder : Ref<IWltDecoder> 照片解码器
     */
    LC_CMD_METHOD(SetWltDecoder)
    {
        Ref<IWltDecoder> wlt = CommandReflectArg(IWltDecoder, arg);
        if(wlt.IsNull())
        {
            _logErr(DeviceError::ArgIsNullErr, "解码器引用为空");
            return false;
        }
        WltDecoder = wlt;
        return true;
    }
    /// 二代证信息格式转换器
    IDCardParser::fpIdcConvert IdcConvert;
    /// 二代证照片解码器
    Ref<IWltDecoder> WltDecoder;
};
//--------------------------------------------------------- 
} // nemespace driver
} // namespace application
} // namespace zhou_yb
//--------------------------------------------------------- 
#endif // _LIBZHOUYB_IDCARDCMDDRIVER_H_
//========================================================= 